#include "precompile.h"

#include "sys/typedef.h"
#include "sys/error.h"
#include "ObjectModel.h"
#include "StringHeap.h"
#include "LoadingManager.h"

ObjectModel::ObjectModel()
	:m_loaderManager(NULL)
{
}

ObjectModel::~ObjectModel()
{
	ClearAll();
	if (m_loaderManager)
		delete m_loaderManager;
	StringHeap::Instance()->Dispose();
}

void ObjectModel::ClearAll()
{
	m_modules.clear();;
	m_creators.clear();
}

vresult	ObjectModel::CreateObject(vclsid clsID,IObject** ppObject)
{
	std::map<vclsid,CreateObjectFuncPtr>::iterator it=m_creators.find(clsID);
	if(it!=m_creators.end())
		return (*((*it).second))(clsID,ppObject);

	return err_notregistered;
}

LoadingManager* ObjectModel::GetLoaderManager(const String& inifilename)
{
	if (!m_loaderManager)
		m_loaderManager = new LoadingManager(inifilename,this);

	return m_loaderManager;
}

vresult ObjectModel::RegisterComponent(const wchar_t* wsComponentName)
{
	String wstrName(wsComponentName);
	_wcsupr_s(const_cast<wchar_t *>(wstrName.data()), wstrName.length() + 1);
	ComponentMap::const_iterator it=m_modules.find(wstrName.c_str());
	if(it!=m_modules.end())
		return vok;

	HMODULE hComponent=LoadLibrary(wstrName.c_str());
	if(!hComponent)
		return err_nomodule;
	m_modules[wstrName.c_str()] = hComponent;
    
	return vok;
}

IObject* ObjectModel::LoadAddin(const wchar_t* modulePath)
{
	String wstrName(modulePath);
	_wcsupr_s(const_cast<wchar_t *>(wstrName.data()), wstrName.length() + 1);

	if (m_addins.find(wstrName.c_str()) != m_addins.end())
		return m_addins[wstrName.c_str()].P();

	if (ISFAILED(RegisterComponent(wstrName.c_str())))
		return NULL;

	HMODULE haddin = m_modules[wstrName.c_str()];
	GetAddinClassFuncPtr func  = (GetAddinClassFuncPtr)::GetProcAddress(haddin,"getAddinClass");
	ASSERT(func);
	if (!func)
		return NULL;

	vclsid addinclsid = func();
	sys::ObjectPtr objAddin;
	objAddin.CreateObject(addinclsid);
	if (objAddin.IsNull())
		return NULL;

	m_addins[wstrName.c_str()] = objAddin;

	return objAddin.P();
}

void ObjectModel::UnloadAddin(const wchar_t* modulePath)
{
	modulePath;
}

void ObjectModel::RegisterCreator(vclsid clsid,CreateObjectFuncPtr func)
{
	m_creators[clsid] = func;
}

void ObjectModel::UnloadAllComponents()
{
	ClearAll();
}

static ObjectModel g_s_System;

SYS_API vresult LoadComponent(const wchar_t* modulePath)
{
	return g_s_System.RegisterComponent(modulePath);
}

SYS_API void UnloadComponent(const wchar_t* modulePath)
{
	modulePath;
}

SYS_API vresult LoadAllComponents(const wchar_t* inifilename)
{
	return g_s_System.GetLoaderManager(inifilename)->LoadAllCategories() ? vok : vfailed;
}

SYS_API void UnloadAllComponents()
{
	g_s_System.UnloadAllComponents();
}

SYS_API vresult CreateObject(vclsid clsID,IObject** ppObject)
{
	return g_s_System.CreateObject(clsID,ppObject);
}

SYS_API void RegisterCreator(vclsid clsid,CreateObjectFuncPtr func)
{
	g_s_System.RegisterCreator(clsid,func);
}

SYS_API IObject* LoadAddin(const wchar_t* modulePath)
{
	return g_s_System.LoadAddin(modulePath);
}

SYS_API void UnloadAddin(const wchar_t* modulePath)
{
	modulePath;
}